﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using WinFromMediaPlayerDemo.Model;
using WinFromMediaPlayerDemo.Model.EventArgs;
namespace WinFromMediaPlayerDemo.Common
{
    /// <summary>
    /// 多文件下载
    /// </summary>
    public class MultiFileDownload
    {

        #region 自定义事件
        /// <summary>
        /// 当前文件下载进度改变
        /// </summary>
        public event EventHandler<CurrentFilePercentageChangedEventArgs> CurrentFilePercentageChanged;
        /// <summary>
        /// 当前文件下载完成
        /// </summary>
        public event EventHandler<CurrentFileCompletedEventArgs> CurrentFileCompleted;

        /// <summary>
        /// 所有文件下载总体进度改变
        /// </summary>
        public event EventHandler<TotalFilesPercentageChangedEventArgs> TotalFilesPercentageChanged;
        /// <summary>
        /// 所有文件下载完成
        /// </summary>
        public event EventHandler<EventArgs> TotalFilesCompleted;

        public event EventHandler<FilePercentageChangedEventArgs> FilePercentageChanged;

        #endregion


        #region 自定义异常
        public class FileDownloadFiledException : Exception
        {
            private string _Message = "";

            public override string Message => _Message;
            public FileDownloadFiledException(string message)
            {
                _Message = message;
            }

        }

        #endregion



        #region 属性
        /// <summary>
        /// 默认分区大小1MB
        /// </summary>
        public uint DefaultPartionSize => 1024000;//1MB
        /// <summary>
        /// 所有文件总大小
        /// </summary>
        public ulong TotalFilesSize { get; private set; }
        /// <summary>
        /// 已下载文件大小
        /// </summary>
        public ulong DownloadFilesSize { get; private set; }
        /// <summary>
        /// 文件总数
        /// </summary>
        public uint FileCount { get; private set; }

        #endregion

        /// <summary>
        /// 文件下载列表
        /// </summary>
        public ConcurrentQueue<RemoteFileInfo> DownloadFiles { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="downloadFileList"></param>
        public MultiFileDownload(ConcurrentQueue<RemoteFileInfo> downloadFileList)
        {
            this.DownloadFiles = downloadFileList;
            this.DownloadFilesSize = 0;
            this.FileCount = (uint)downloadFileList.Count;
            foreach (var item in downloadFileList)
            {
                TotalFilesSize += item.FileSize;
            }
        }

        public void Run()
        {
            RemoteFileInfo currentFileInfo;
            bool result = DownloadFiles.TryDequeue(out currentFileInfo);
            if (!result || currentFileInfo == null)
            {
                throw new FileDownloadFiledException("文件队列为空");
            }
            DownloadPerFile(currentFileInfo);
        }

        /// <summary>
        /// 根据文件大小，智能计算文件分区大小
        /// </summary>
        /// <param name="fileSize"></param>
        /// <param name="partionSize">指定的分区大小</param>
        /// <returns></returns>
        private uint ComputePartionCount(ulong fileSize, ulong partionSize)
        {
            uint partionCount = 1;
            if (fileSize % partionSize == 0)//整除
            {
                partionCount = (uint)(fileSize / partionSize);
            }
            partionCount = (uint)(fileSize / partionSize + 1);
            return partionCount;
        }

        /// <summary>
        /// 从队列中拿到文件下载
        /// </summary>
        private void DownloadPerFile(RemoteFileInfo currentFileInfo)
        {
            //计算文件分片大小
            uint partionCount = ComputePartionCount(currentFileInfo.FileSize, DefaultPartionSize);
            currentFileInfo.TotalPartionCount = partionCount;
            ulong tempFileSize = currentFileInfo.FileSize;
            string baseUri = "http://upload.kingkwok.com/Video/Download/";
            //循环下载每一片数据
            for (uint i = 0; i < partionCount; i++)
            {
                using (WebClient client = new WebClient())
                {
                    uint requestFileSize = DefaultPartionSize;
                    if (tempFileSize < DefaultPartionSize)
                    {
                        requestFileSize = (uint)tempFileSize;
                    }
                    else
                    {
                        tempFileSize -= DefaultPartionSize;
                    }
                    //Console.WriteLine($"{currentFileInfo.FileName}===={requestFileSize}");
                    Uri downUri = new Uri($"{baseUri}?fileName={currentFileInfo.FileName}&startIndex={(i + i * requestFileSize)}&size={requestFileSize}");
                    //分区文件下载完成事件
                    client.DownloadDataCompleted += Client_DownloadDataCompleted;
                    client.DownloadDataAsync(downUri, new PartionFileInfo()
                    {
                        FileInfo = currentFileInfo,
                        PartionIndex = i,
                        PartionStatu = -1,
                        PartionSize = requestFileSize
                    });
                    
                }
            }
        }
        /// <summary>
        /// 文件分区快下载完成事件实现
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            PartionFileInfo pFileInfo = e.UserState as PartionFileInfo;
            if (pFileInfo == null)
            {
                return;
            }
            ////更新文件下载进度
            this.DownloadFilesSize += pFileInfo.PartionSize;

            byte currentFilePercentage = (byte)Math.Floor((pFileInfo.PartionIndex + 1) / (decimal)pFileInfo.FileInfo.TotalPartionCount * 100);
            byte totalFilesPercentage = (byte)(Math.Floor(this.DownloadFilesSize / (decimal)this.TotalFilesSize * 100));
            FilePercentageChangedEventArgs arg = new FilePercentageChangedEventArgs()
            {
                FileIndex = pFileInfo.FileInfo.FileIndex,
                FileCount = this.FileCount,
                CurrentFilePercentage = currentFilePercentage,
                FileInfo = pFileInfo.FileInfo,
                TotalFilesPercentage = totalFilesPercentage,
                Data = e.Result,
                PartionIndex = pFileInfo.PartionIndex
            };
            Console.WriteLine($"{pFileInfo.PartionIndex}/{pFileInfo.FileInfo.TotalPartionCount}");
            FilePercentageChanged?.Invoke(this, arg);
            if(currentFilePercentage == 100 && !DownloadFiles.IsEmpty)
            {
                Run();
            }


            ////更新文件下载进度
            //this.DownloadFilesSize += pFileInfo.PartionSize;
            ////发布当前文件下载进度改变事件
            //CurrentFilePercentageChanged?.Invoke(this, new CurrentFilePercentageChangedEventArgs()
            //{
            //    FileInfo = pFileInfo.FileInfo,
            //    Percentage = (byte)Math.Floor((pFileInfo.PartionIndex+1) / (decimal)pFileInfo.FileInfo.TotalPartionCount* 100)
            //});
            ////Console.WriteLine($"{pFileInfo.PartionIndex}/{pFileInfo.FileInfo.TotalPartionCount}======={(pFileInfo.PartionIndex + 1) / (decimal)pFileInfo.FileInfo.TotalPartionCount}");
            ////该文件所有分片已下载完毕
            //if (pFileInfo.PartionIndex+1 == pFileInfo.FileInfo.TotalPartionCount)
            //{
            //    //发布当前文件下载完成事件
            //    CurrentFileCompleted?.Invoke(this, new CurrentFileCompletedEventArgs()
            //    {
            //        FileInfo = pFileInfo.FileInfo,
            //        Percentage = 100
            //    });
            //    //发布文件总体进度改变事件
            //    TotalFilesPercentageChanged?.Invoke(this, new TotalFilesPercentageChangedEventArgs()
            //    {
            //        FileCount = this.FileCount,
            //        FileIndex = pFileInfo.FileInfo.FileIndex,
            //        Percentage = (byte)(Math.Floor(this.DownloadFilesSize / (decimal)this.TotalFilesSize * 100))
            //    });
            //    //所有文件下载完成事件
            //    if (pFileInfo.FileInfo.FileIndex +1 == this.FileCount)
            //    {
            //        TotalFilesCompleted?.Invoke(this, new EventArgs());
            //        return;
            //    }
            //    //从队列中去取出下一个文件
            //    Run();
            //}

   
        }
    }
}
